home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / gfx / x11 / twm_930531.lha / twm / add_window.c next >
C/C++ Source or Header  |  1993-05-30  |  45KB  |  1,522 lines

  1. /*****************************************************************************/
  2. /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
  3. /**                          Salt Lake City, Utah                           **/
  4. /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
  5. /**                        Cambridge, Massachusetts                         **/
  6. /**                                                                         **/
  7. /**                           All Rights Reserved                           **/
  8. /**                                                                         **/
  9. /**    Permission to use, copy, modify, and distribute this software and    **/
  10. /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
  11. /**    granted, provided that the above copyright notice appear  in  all    **/
  12. /**    copies and that both  that  copyright  notice  and  this  permis-    **/
  13. /**    sion  notice appear in supporting  documentation,  and  that  the    **/
  14. /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
  15. /**    in publicity pertaining to distribution of the  software  without    **/
  16. /**    specific, written prior permission.                                  **/
  17. /**                                                                         **/
  18. /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
  19. /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
  20. /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
  21. /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
  22. /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
  23. /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
  24. /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
  25. /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
  26. /*****************************************************************************/
  27.  
  28.  
  29. /**********************************************************************
  30.  *
  31.  * $XConsortium: add_window.c,v 1.153 91/07/10 13:17:26 dave Exp $
  32.  *
  33.  * Add a new window, put the titlbar and other stuff around
  34.  * the window
  35.  *
  36.  * 31-Mar-88 Tom LaStrange        Initial Version.
  37.  *
  38.  **********************************************************************/
  39.  
  40. #include <stdio.h>
  41. #include "twm.h"
  42. #include <X11/Xatom.h>
  43. #include "add_window.h"
  44. #include "util.h"
  45. #include "resize.h"
  46. #include "parse.h"
  47. #include "list.h"
  48. #include "events.h"
  49. #include "menus.h"
  50. #include "screen.h"
  51. #include "iconmgr.h"
  52.  
  53. #define gray_width 2
  54. #define gray_height 2
  55. static char gray_bits[] = {
  56.    0x02, 0x01};
  57.  
  58. int AddingX;
  59. int AddingY;
  60. int AddingW;
  61. int AddingH;
  62.  
  63. static int PlaceX = 50;
  64. static int PlaceY = 50;
  65. static void CreateWindowTitlebarButtons();
  66.  
  67. char NoName[] = "Untitled"; /* name if no name is specified */
  68.  
  69.  
  70. /************************************************************************
  71.  *
  72.  *  Procedure:
  73.  *    GetGravityOffsets - map gravity to (x,y) offset signs for adding
  74.  *        to x and y when window is mapped to get proper placement.
  75.  * 
  76.  ************************************************************************
  77.  */
  78.  
  79. GetGravityOffsets (tmp, xp, yp)
  80.     TwmWindow *tmp;            /* window from which to get gravity */
  81.     int *xp, *yp;            /* return values */
  82. {
  83.     static struct _gravity_offset {
  84.     int x, y;
  85.     } gravity_offsets[11] = {
  86.     {  0,  0 },            /* ForgetGravity */
  87.     { -1, -1 },            /* NorthWestGravity */
  88.     {  0, -1 },            /* NorthGravity */
  89.     {  1, -1 },            /* NorthEastGravity */
  90.     { -1,  0 },            /* WestGravity */
  91.     {  0,  0 },            /* CenterGravity */
  92.     {  1,  0 },            /* EastGravity */
  93.     { -1,  1 },            /* SouthWestGravity */
  94.     {  0,  1 },            /* SouthGravity */
  95.     {  1,  1 },            /* SouthEastGravity */
  96.     {  0,  0 },            /* StaticGravity */
  97.     };
  98.     register int g = ((tmp->hints.flags & PWinGravity) 
  99.               ? tmp->hints.win_gravity : NorthWestGravity);
  100.  
  101.     if (g < ForgetGravity || g > StaticGravity) {
  102.     *xp = *yp = 0;
  103.     } else {
  104.     *xp = gravity_offsets[g].x;
  105.     *yp = gravity_offsets[g].y;
  106.     }
  107. }
  108.  
  109.  
  110.  
  111.  
  112. /***********************************************************************
  113.  *
  114.  *  Procedure:
  115.  *    AddWindow - add a new window to the twm list
  116.  *
  117.  *  Returned Value:
  118.  *    (TwmWindow *) - pointer to the TwmWindow structure
  119.  *
  120.  *  Inputs:
  121.  *    w    - the window id of the window to add
  122.  *    iconm    - flag to tell if this is an icon manager window
  123.  *    iconp    - pointer to icon manager struct
  124.  *
  125.  ***********************************************************************
  126.  */
  127.  
  128. TwmWindow *
  129. AddWindow(w, iconm, iconp)
  130. Window w;
  131. int iconm;
  132. IconMgr *iconp;
  133. {
  134.     TwmWindow *tmp_win;            /* new twm window structure */
  135.     int stat;
  136.     XEvent event;
  137.     unsigned long valuemask;        /* mask for create windows */
  138.     XSetWindowAttributes attributes;    /* attributes for create windows */
  139.     int width, height;            /* tmp variable */
  140.     Atom actual_type;
  141.     int actual_format;
  142.     unsigned long nitems, bytesafter;
  143.     int ask_user;        /* don't know where to put the window */
  144.     int gravx, gravy;            /* gravity signs for positioning */
  145.     int namelen;
  146.     int bw2;
  147.  
  148. #ifdef DEBUG
  149.     fprintf(stderr, "AddWindow: w = 0x%x\n", w);
  150. #endif
  151.  
  152.     /* allocate space for the twm window */
  153.     tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow));
  154.     if (tmp_win == 0)
  155.     {
  156.     fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n",
  157.          ProgramName, w);
  158.     return NULL;
  159.     }
  160.     tmp_win->w = w;
  161.     tmp_win->zoomed = ZOOM_NONE;
  162.     tmp_win->iconmgr = iconm;
  163.     tmp_win->iconmgrp = iconp;
  164.     tmp_win->cmaps.number_cwins = 0;
  165.  
  166.     XSelectInput(dpy, tmp_win->w, PropertyChangeMask);
  167.     XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr);
  168.     XFetchName(dpy, tmp_win->w, &tmp_win->name);
  169.     tmp_win->class = NoClass;
  170.     XGetClassHint(dpy, tmp_win->w, &tmp_win->class);
  171.     FetchWmProtocols (tmp_win);
  172.     FetchWmColormapWindows (tmp_win);
  173.  
  174.     /*
  175.      * do initial clip; should look at window gravity
  176.      */
  177.     if (tmp_win->attr.width > Scr->MaxWindowWidth)
  178.       tmp_win->attr.width = Scr->MaxWindowWidth;
  179.     if (tmp_win->attr.height > Scr->MaxWindowHeight)
  180.       tmp_win->attr.height = Scr->MaxWindowHeight;
  181.  
  182.     tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
  183.     if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint)) 
  184.       tmp_win->group = tmp_win->wmhints->window_group;
  185.     else
  186.     tmp_win->group = tmp_win->w/* NULL */;
  187.  
  188.     /*
  189.      * The July 27, 1988 draft of the ICCCM ignores the size and position
  190.      * fields in the WM_NORMAL_HINTS property.
  191.      */
  192.  
  193.     tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor);
  194.  
  195.     if (tmp_win->name == NULL)
  196.     tmp_win->name = NoName;
  197.     if (tmp_win->class.res_name == NULL)
  198.         tmp_win->class.res_name = NoName;
  199.     if (tmp_win->class.res_class == NULL)
  200.         tmp_win->class.res_class = NoName;
  201.  
  202.     tmp_win->full_name = tmp_win->name;
  203.     namelen = strlen (tmp_win->name);
  204.  
  205.     tmp_win->highlight = Scr->Highlight && 
  206.     (!(short)(int) LookInList(Scr->NoHighlight, tmp_win->full_name, 
  207.         &tmp_win->class));
  208.  
  209.     tmp_win->stackmode = Scr->StackMode &&
  210.     (!(short)(int) LookInList(Scr->NoStackModeL, tmp_win->full_name, 
  211.         &tmp_win->class));
  212.  
  213.     tmp_win->titlehighlight = Scr->TitleHighlight && 
  214.     (!(short)(int) LookInList(Scr->NoTitleHighlight, tmp_win->full_name, 
  215.         &tmp_win->class));
  216.  
  217.     tmp_win->auto_raise = (short)(int) LookInList(Scr->AutoRaise, 
  218.                           tmp_win->full_name,
  219.                         &tmp_win->class);
  220.     if (tmp_win->auto_raise) Scr->NumAutoRaises++;
  221.     tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping;
  222.     if (Scr->IconifyByUnmapping)
  223.     {
  224.     tmp_win->iconify_by_unmapping = iconm ? FALSE :
  225.         !(short)(int) LookInList(Scr->DontIconify, tmp_win->full_name,
  226.         &tmp_win->class);
  227.     }
  228.     tmp_win->iconify_by_unmapping |= 
  229.     (short)(int) LookInList(Scr->IconifyByUn, tmp_win->full_name,
  230.         &tmp_win->class);
  231.  
  232.     if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) {
  233.     if (Scr->Ring) {
  234.         tmp_win->ring.next = Scr->Ring->ring.next;
  235.         if (Scr->Ring->ring.next->ring.prev)
  236.           Scr->Ring->ring.next->ring.prev = tmp_win;
  237.         Scr->Ring->ring.next = tmp_win;
  238.         tmp_win->ring.prev = Scr->Ring;
  239.     } else {
  240.         tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
  241.     }
  242.     } else
  243.       tmp_win->ring.next = tmp_win->ring.prev = NULL;
  244.     tmp_win->ring.cursor_valid = False;
  245.  
  246.     tmp_win->squeeze_info = NULL;
  247.     /*
  248.      * get the squeeze information; note that this does not have to be freed
  249.      * since it is coming from the screen list
  250.      */
  251.     if (HasShape) {
  252.     if (!LookInList (Scr->DontSqueezeTitleL, tmp_win->full_name, 
  253.              &tmp_win->class)) {
  254.         tmp_win->squeeze_info = (SqueezeInfo *)
  255.           LookInList (Scr->SqueezeTitleL, tmp_win->full_name,
  256.               &tmp_win->class);
  257.         if (!tmp_win->squeeze_info) {
  258.         static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 };
  259.         if (Scr->SqueezeTitle)
  260.           tmp_win->squeeze_info = &default_squeeze;
  261.         }
  262.     }
  263.       }
  264.  
  265.     tmp_win->old_bw = tmp_win->attr.border_width;
  266.  
  267.     if (Scr->ClientBorderWidth) {
  268.         tmp_win->frame_bw = tmp_win->old_bw;
  269.     } else {
  270.         tmp_win->frame_bw = Scr->BorderWidth;
  271.     }
  272.     bw2 = tmp_win->frame_bw * 2;
  273.  
  274.     tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
  275.     if (Scr->NoTitlebar)
  276.         tmp_win->title_height = 0;
  277.     if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class))
  278.         tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
  279.     if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class))
  280.         tmp_win->title_height = 0;
  281.  
  282.     /* if it is a transient window, don't put a title on it */
  283.     if (tmp_win->transient && !Scr->DecorateTransients)
  284.     tmp_win->title_height = 0;
  285.  
  286.     if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class))
  287.     {
  288.     if (!tmp_win->wmhints)
  289.     {
  290.         tmp_win->wmhints = (XWMHints *)malloc(sizeof(XWMHints));
  291.         tmp_win->wmhints->flags = 0;
  292.     }
  293.     tmp_win->wmhints->initial_state = IconicState;
  294.     tmp_win->wmhints->flags |= StateHint;
  295.     }
  296.  
  297.     GetWindowSizeHints (tmp_win);
  298.     GetGravityOffsets (tmp_win, &gravx, &gravy);
  299.  
  300.     /*
  301.      * Don't bother user if:
  302.      * 
  303.      *     o  the window is a transient, or
  304.      * 
  305.      *     o  a USPosition was requested, or
  306.      * 
  307.      *     o  a PPosition was requested and UsePPosition is ON or
  308.      *        NON_ZERO if the window is at other than (0,0)
  309.      */
  310.     ask_user = TRUE;
  311.     if (tmp_win->transient || 
  312.     (tmp_win->hints.flags & USPosition) ||
  313.         ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition &&
  314.      (Scr->UsePPosition == PPOS_ON || 
  315.       tmp_win->attr.x != 0 || tmp_win->attr.y != 0)))
  316.       ask_user = FALSE;
  317.  
  318.     /*
  319.      * do any prompting for position
  320.      */
  321.     if (HandlingEvents && ask_user) {
  322.       if (Scr->RandomPlacement) {    /* just stick it somewhere */
  323.     if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth)
  324.         PlaceX = 50;
  325.     if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight)
  326.         PlaceY = 50;
  327.  
  328.     tmp_win->attr.x = PlaceX;
  329.     tmp_win->attr.y = PlaceY;
  330.     PlaceX += 30;
  331.     PlaceY += 30;
  332.       } else {                /* else prompt */
  333.     if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint &&
  334.           tmp_win->wmhints->initial_state == IconicState))
  335.     {
  336.         Bool firsttime = True;
  337.  
  338.         /* better wait until all the mouse buttons have been 
  339.          * released.
  340.          */
  341.         while (TRUE)
  342.         {
  343.         XUngrabServer(dpy);
  344.         XSync(dpy, 0);
  345.         XGrabServer(dpy);
  346.  
  347.         JunkMask = 0;
  348.         if (!XQueryPointer (dpy, Scr->Root, &JunkRoot, 
  349.                     &JunkChild, &JunkX, &JunkY,
  350.                     &AddingX, &AddingY, &JunkMask))
  351.           JunkMask = 0;
  352.  
  353.         JunkMask &= (Button1Mask | Button2Mask | Button3Mask |
  354.                  Button4Mask | Button5Mask);
  355.  
  356.         /*
  357.          * watch out for changing screens
  358.          */
  359.         if (firsttime) {
  360.             if (JunkRoot != Scr->Root) {
  361.             register int scrnum;
  362.  
  363.             for (scrnum = 0; scrnum < NumScreens; scrnum++) {
  364.                 if (JunkRoot == RootWindow (dpy, scrnum)) break;
  365.             }
  366.  
  367.             if (scrnum != NumScreens) PreviousScreen = scrnum;
  368.             }
  369.             firsttime = False;
  370.         }
  371.  
  372.         /*
  373.          * wait for buttons to come up; yuck
  374.          */
  375.         if (JunkMask != 0) continue;
  376.  
  377.         /* 
  378.          * this will cause a warp to the indicated root
  379.          */
  380.         stat = XGrabPointer(dpy, Scr->Root, False,
  381.             ButtonPressMask | ButtonReleaseMask |
  382.             PointerMotionMask | PointerMotionHintMask,
  383.             GrabModeAsync, GrabModeAsync,
  384.             Scr->Root, UpperLeftCursor, CurrentTime);
  385.  
  386.         if (stat == GrabSuccess)
  387.             break;
  388.         }
  389.  
  390.         width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
  391.                         tmp_win->name, namelen));
  392.         height = Scr->SizeFont.height + SIZE_VINDENT * 2;
  393.         
  394.         XResizeWindow (dpy, Scr->SizeWindow, width + SIZE_HINDENT, height);
  395.         XMapRaised(dpy, Scr->SizeWindow);
  396.         InstallRootColormap();
  397.  
  398.         FBF(Scr->DefaultC.fore, Scr->DefaultC.back,
  399.         Scr->SizeFont.font->fid);
  400.         XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC,
  401.                   SIZE_HINDENT,
  402.                   SIZE_VINDENT + Scr->SizeFont.font->ascent,
  403.                   tmp_win->name, namelen);
  404.  
  405.         AddingW = tmp_win->attr.width + bw2;
  406.         AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
  407.  
  408.         MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
  409.                 tmp_win->frame_bw, tmp_win->title_height);
  410.  
  411.         while (TRUE)
  412.         {
  413.         XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event);
  414.  
  415.         if (Event.type == MotionNotify) {
  416.             /* discard any extra motion events before a release */
  417.             while(XCheckMaskEvent(dpy,
  418.             ButtonMotionMask | ButtonPressMask, &Event))
  419.             if (Event.type == ButtonPress)
  420.                 break;
  421.         }
  422.         
  423.         if (event.type == ButtonPress) {
  424.           AddingX = event.xbutton.x_root;
  425.           AddingY = event.xbutton.y_root;
  426.           
  427.           /* DontMoveOff prohibits user form off-screen placement */
  428.           if (Scr->DontMoveOff)    
  429.               {
  430.               int AddingR, AddingB;
  431.               
  432.               AddingR = AddingX + AddingW;
  433.               AddingB = AddingY + AddingH;
  434.               
  435.               if (AddingX < 0)
  436.             AddingX = 0;
  437.               if (AddingR > Scr->MyDisplayWidth)
  438.             AddingX = Scr->MyDisplayWidth - AddingW;
  439.               
  440.               if (AddingY < 0)
  441.             AddingY = 0;
  442.               if (AddingB > Scr->MyDisplayHeight)
  443.             AddingY = Scr->MyDisplayHeight - AddingH;
  444.               
  445.              }
  446.           break;
  447.         }
  448.  
  449.         if (event.type != MotionNotify) {
  450.             continue;
  451.         }
  452.  
  453.         XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
  454.             &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
  455.  
  456.         if (Scr->DontMoveOff)
  457.         {
  458.             int AddingR, AddingB;
  459.  
  460.             AddingR = AddingX + AddingW;
  461.             AddingB = AddingY + AddingH;
  462.             
  463.             if (AddingX < 0)
  464.                 AddingX = 0;
  465.             if (AddingR > Scr->MyDisplayWidth)
  466.                 AddingX = Scr->MyDisplayWidth - AddingW;
  467.  
  468.             if (AddingY < 0)
  469.             AddingY = 0;
  470.             if (AddingB > Scr->MyDisplayHeight)
  471.             AddingY = Scr->MyDisplayHeight - AddingH;
  472.         }
  473.  
  474.         MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
  475.                 tmp_win->frame_bw, tmp_win->title_height);
  476.  
  477.         }
  478.  
  479.         if (event.xbutton.button == Button2) {
  480.         int lastx, lasty;
  481.  
  482.         Scr->SizeStringOffset = width +
  483.           XTextWidth(Scr->SizeFont.font, ": ", 2);
  484.         XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
  485.                    Scr->SizeStringWidth, height);
  486.         XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width,
  487.                   SIZE_VINDENT + Scr->SizeFont.font->ascent,
  488.                   ": ", 2);
  489.         if (0/*Scr->AutoRelativeResize*/) {
  490.             int dx = (tmp_win->attr.width / 4);
  491.             int dy = (tmp_win->attr.height / 4);
  492.             
  493. #define HALF_AVE_CURSOR_SIZE 8        /* so that it is visible */
  494.             if (dx < HALF_AVE_CURSOR_SIZE) dx = HALF_AVE_CURSOR_SIZE;
  495.             if (dy < HALF_AVE_CURSOR_SIZE) dy = HALF_AVE_CURSOR_SIZE;
  496. #undef HALF_AVE_CURSOR_SIZE
  497.             dx += (tmp_win->frame_bw + 1);
  498.             dy += (bw2 + tmp_win->title_height + 1);
  499.             if (AddingX + dx >= Scr->MyDisplayWidth)
  500.               dx = Scr->MyDisplayWidth - AddingX - 1;
  501.             if (AddingY + dy >= Scr->MyDisplayHeight)
  502.               dy = Scr->MyDisplayHeight - AddingY - 1;
  503.             if (dx > 0 && dy > 0)
  504.               XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy);
  505.         } else {
  506.             XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0,
  507.                   AddingX + AddingW/2, AddingY + AddingH/2);
  508.         }
  509.         AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH);
  510.  
  511.         lastx = -10000;
  512.         lasty = -10000;
  513.         while (TRUE)
  514.         {
  515.             XMaskEvent(dpy,
  516.                    ButtonReleaseMask | ButtonMotionMask, &event);
  517.  
  518.             if (Event.type == MotionNotify) {
  519.             /* discard any extra motion events before a release */
  520.             while(XCheckMaskEvent(dpy,
  521.                 ButtonMotionMask | ButtonReleaseMask, &Event))
  522.                 if (Event.type == ButtonRelease)
  523.                 break;
  524.             }
  525.  
  526.             if (event.type == ButtonRelease)
  527.             {
  528.             AddEndResize(tmp_win);
  529.             break;
  530.             }
  531.  
  532.             if (event.type != MotionNotify) {
  533.             continue;
  534.             }
  535.  
  536.             /*
  537.              * XXX - if we are going to do a loop, we ought to consider
  538.              * using multiple GXxor lines so that we don't need to 
  539.              * grab the server.
  540.              */
  541.             XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
  542.             &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
  543.  
  544.             if (lastx != AddingX || lasty != AddingY)
  545.             {
  546.             DoResize(AddingX, AddingY, tmp_win);
  547.  
  548.             lastx = AddingX;
  549.             lasty = AddingY;
  550.             }
  551.  
  552.         }
  553.         } 
  554.         else if (event.xbutton.button == Button3)
  555.         {
  556.         int maxw = Scr->MyDisplayWidth - AddingX - bw2;
  557.         int maxh = Scr->MyDisplayHeight - AddingY - bw2;
  558.  
  559.         /*
  560.          * Make window go to bottom of screen, and clip to right edge.
  561.          * This is useful when popping up large windows and fixed
  562.          * column text windows.
  563.          */
  564.         if (AddingW > maxw) AddingW = maxw;
  565.         AddingH = maxh;
  566.  
  567.         ConstrainSize (tmp_win, &AddingW, &AddingH);  /* w/o borders */
  568.         AddingW += bw2;
  569.         AddingH += bw2;
  570.         }
  571.         else
  572.         {
  573.         XMaskEvent(dpy, ButtonReleaseMask, &event);
  574.         }
  575.  
  576.         MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
  577.         XUnmapWindow(dpy, Scr->SizeWindow);
  578.         UninstallRootColormap();
  579.         XUngrabPointer(dpy, CurrentTime);
  580.  
  581.         tmp_win->attr.x = AddingX;
  582.         tmp_win->attr.y = AddingY + tmp_win->title_height;
  583.         tmp_win->attr.width = AddingW - bw2;
  584.         tmp_win->attr.height = AddingH - tmp_win->title_height - bw2;
  585.  
  586.         XUngrabServer(dpy);
  587.     }
  588.       }
  589.     } else {                /* put it where asked, mod title bar */
  590.     /* if the gravity is towards the top, move it by the title height */
  591.     if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height;
  592.     }
  593.  
  594.  
  595. #ifdef DEBUG
  596.     fprintf(stderr, "  position window  %d, %d  %dx%d\n", 
  597.         tmp_win->attr.x,
  598.         tmp_win->attr.y,
  599.         tmp_win->attr.width,
  600.         tmp_win->attr.height);
  601. #endif
  602.  
  603.     if (!Scr->ClientBorderWidth) {    /* need to adjust for twm borders */
  604.     int delta = tmp_win->attr.border_width - tmp_win->frame_bw;
  605.     tmp_win->attr.x += gravx * delta;
  606.     tmp_win->attr.y += gravy * delta;
  607.     }
  608.  
  609.     tmp_win->title_width = tmp_win->attr.width;
  610.  
  611.     if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0);
  612.  
  613.     tmp_win->name_width = XTextWidth(Scr->TitleBarFont.font, tmp_win->name,
  614.                      namelen);
  615.  
  616.     if (XGetWindowProperty (dpy, tmp_win->w, XA_WM_ICON_NAME, 0L, 200L, False,
  617.                 XA_STRING, &actual_type, &actual_format, &nitems,
  618.                 &bytesafter,(unsigned char **)&tmp_win->icon_name))
  619.     tmp_win->icon_name = tmp_win->name;
  620.  
  621.     if (tmp_win->icon_name == NULL)
  622.     tmp_win->icon_name = tmp_win->name;
  623.  
  624.     tmp_win->iconified = FALSE;
  625.     tmp_win->icon = FALSE;
  626.     tmp_win->icon_on = FALSE;
  627.  
  628.     XGrabServer(dpy);
  629.  
  630.     /*
  631.      * Make sure the client window still exists.  We don't want to leave an
  632.      * orphan frame window if it doesn't.  Since we now have the server 
  633.      * grabbed, the window can't disappear later without having been 
  634.      * reparented, so we'll get a DestroyNotify for it.  We won't have 
  635.      * gotten one for anything up to here, however.
  636.      */
  637.     if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
  638.              &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
  639.     {
  640.     free((char *)tmp_win);
  641.     XUngrabServer(dpy);
  642.     return(NULL);
  643.     }
  644.  
  645.     /* add the window into the twm list */
  646.     tmp_win->next = Scr->TwmRoot.next;
  647.     if (Scr->TwmRoot.next != NULL)
  648.     Scr->TwmRoot.next->prev = tmp_win;
  649.     tmp_win->prev = &Scr->TwmRoot;
  650.     Scr->TwmRoot.next = tmp_win;
  651.  
  652.     /* get all the colors for the window */
  653.  
  654.     tmp_win->border = Scr->BorderColor;
  655.     tmp_win->icon_border = Scr->IconBorderColor;
  656.     tmp_win->border_tile.fore = Scr->BorderTileC.fore;
  657.     tmp_win->border_tile.back = Scr->BorderTileC.back;
  658.     tmp_win->title.fore = Scr->TitleC.fore;
  659.     tmp_win->title.back = Scr->TitleC.back;
  660.     tmp_win->iconc.fore = Scr->IconC.fore;
  661.     tmp_win->iconc.back = Scr->IconC.back;
  662.  
  663.     GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class,
  664.     &tmp_win->border);
  665.     GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name, &tmp_win->class,
  666.     &tmp_win->icon_border);
  667.     GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name,
  668.     &tmp_win->class, &tmp_win->border_tile.fore);
  669.     GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name,
  670.     &tmp_win->class, &tmp_win->border_tile.back);
  671.     GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class,
  672.     &tmp_win->title.fore);
  673.     GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class,
  674.     &tmp_win->title.back);
  675.     GetColorFromList(Scr->IconForegroundL, tmp_win->full_name, &tmp_win->class,
  676.     &tmp_win->iconc.fore);
  677.     GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name, &tmp_win->class,
  678.     &tmp_win->iconc.back);
  679.  
  680.  
  681.     /* create windows */
  682.  
  683.     tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw;
  684.     tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height +
  685.     tmp_win->old_bw - tmp_win->frame_bw;
  686.     tmp_win->frame_width = tmp_win->attr.width;
  687.     tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height;
  688.  
  689.     valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask;
  690.     attributes.background_pixmap = None;
  691.     attributes.border_pixel = tmp_win->border;
  692.     attributes.cursor = Scr->FrameCursor;
  693.     attributes.event_mask = (SubstructureRedirectMask | 
  694.                  ButtonPressMask | ButtonReleaseMask |
  695.                  EnterWindowMask | LeaveWindowMask);
  696.     if (tmp_win->attr.save_under) {
  697.     attributes.save_under = True;
  698.     valuemask |= CWSaveUnder;
  699.     }
  700.  
  701.     tmp_win->frame = XCreateWindow (dpy, Scr->Root, tmp_win->frame_x,
  702.                     tmp_win->frame_y, 
  703.                     (unsigned int) tmp_win->frame_width,
  704.                     (unsigned int) tmp_win->frame_height,
  705.                     (unsigned int) tmp_win->frame_bw,
  706.                     Scr->d_depth,
  707.                     (unsigned int) CopyFromParent,
  708.                     Scr->d_visual, valuemask, &attributes);
  709.     
  710.     if (tmp_win->title_height)
  711.     {
  712.     valuemask = (CWEventMask | CWBorderPixel | CWBackPixel);
  713.     attributes.event_mask = (KeyPressMask | ButtonPressMask |
  714.                  ButtonReleaseMask | ExposureMask);
  715.     attributes.border_pixel = tmp_win->border;
  716.     attributes.background_pixel = tmp_win->title.back;
  717.     tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame, 
  718.                       -tmp_win->frame_bw,
  719.                       -tmp_win->frame_bw,
  720.                       (unsigned int) tmp_win->attr.width, 
  721.                       (unsigned int) Scr->TitleHeight,
  722.                       (unsigned int) tmp_win->frame_bw,
  723.                       Scr->d_depth,
  724.                       (unsigned int) CopyFromParent,
  725.                       Scr->d_visual, valuemask,
  726.                       &attributes);
  727.     }
  728.     else {
  729.     tmp_win->title_w = 0;
  730.     tmp_win->squeeze_info = NULL;
  731.     }
  732.  
  733.     if (tmp_win->highlight)
  734.     {
  735.     tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root, 
  736.         gray_bits, gray_width, gray_height, 
  737.         tmp_win->border_tile.fore, tmp_win->border_tile.back,
  738.         Scr->d_depth);
  739.  
  740.     SetBorder (tmp_win, False);
  741.     }
  742.     else
  743.     tmp_win->gray = None;
  744.  
  745.     
  746.     if (tmp_win->title_w) {
  747.     CreateWindowTitlebarButtons (tmp_win);
  748.     ComputeTitleLocation (tmp_win);
  749.     XMoveWindow (dpy, tmp_win->title_w,
  750.              tmp_win->title_x, tmp_win->title_y);
  751.     XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor);
  752.     }
  753.  
  754.     valuemask = (CWEventMask | CWDontPropagate);
  755.     attributes.event_mask = (StructureNotifyMask | PropertyChangeMask |
  756.                  ColormapChangeMask | VisibilityChangeMask |
  757.                  EnterWindowMask | LeaveWindowMask);
  758.     attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
  759.     XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes);
  760.  
  761.     if (HasShape)
  762.     XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
  763.     
  764.     if (tmp_win->title_w) {
  765.     XMapWindow (dpy, tmp_win->title_w);
  766.     }
  767.  
  768.     if (HasShape) {
  769.     int xws, yws, xbs, ybs;
  770.     unsigned wws, hws, wbs, hbs;
  771.     int boundingShaped, clipShaped;
  772.  
  773.     XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
  774.     XShapeQueryExtents (dpy, tmp_win->w,
  775.                 &boundingShaped, &xws, &yws, &wws, &hws,
  776.                 &clipShaped, &xbs, &ybs, &wbs, &hbs);
  777.     tmp_win->wShaped = boundingShaped;
  778.     }
  779.  
  780.     if (!tmp_win->iconmgr)
  781.     XAddToSaveSet(dpy, tmp_win->w);
  782.     
  783.     XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height);
  784.     /*
  785.      * Reparenting generates an UnmapNotify event, followed by a MapNotify.
  786.      * Set the map state to FALSE to prevent a transition back to
  787.      * WithdrawnState in HandleUnmapNotify.  Map state gets set correctly
  788.      * again in HandleMapNotify.
  789.      */
  790.     tmp_win->mapped = FALSE;
  791.  
  792.     SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y,
  793.         tmp_win->frame_width, tmp_win->frame_height, -1, True);
  794.  
  795.     /* wait until the window is iconified and the icon window is mapped
  796.      * before creating the icon window 
  797.      */
  798.     tmp_win->icon_w = NULL;
  799.  
  800.     if (!tmp_win->iconmgr)
  801.     {
  802.     GrabButtons(tmp_win);
  803.     GrabKeys(tmp_win);
  804.     }
  805.  
  806.     (void) AddIconManager(tmp_win);
  807.  
  808.     XSaveContext(dpy, tmp_win->w, TwmContext, (caddr_t) tmp_win);
  809.     XSaveContext(dpy, tmp_win->w, ScreenContext, (caddr_t) Scr);
  810.     XSaveContext(dpy, tmp_win->frame, TwmContext, (caddr_t) tmp_win);
  811.     XSaveContext(dpy, tmp_win->frame, ScreenContext, (caddr_t) Scr);
  812.     if (tmp_win->title_height)
  813.     {
  814.     int i;
  815.     int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  816.  
  817.     XSaveContext(dpy, tmp_win->title_w, TwmContext, (caddr_t) tmp_win);
  818.     XSaveContext(dpy, tmp_win->title_w, ScreenContext, (caddr_t) Scr);
  819.     for (i = 0; i < nb; i++) {
  820.         XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext,
  821.              (caddr_t) tmp_win);
  822.         XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext,
  823.              (caddr_t) Scr);
  824.     }
  825.     if (tmp_win->hilite_w)
  826.     {
  827.         XSaveContext(dpy, tmp_win->hilite_w, TwmContext, (caddr_t)tmp_win);
  828.         XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (caddr_t)Scr);
  829.     }
  830.     }
  831.  
  832.     XUngrabServer(dpy);
  833.  
  834.     /* if we were in the middle of a menu activated function, regrab
  835.      * the pointer 
  836.      */
  837.     if (RootFunction)
  838.     ReGrab();
  839.  
  840.     return (tmp_win);
  841. }
  842.  
  843.  
  844. /***********************************************************************
  845.  *
  846.  *  Procedure:
  847.  *    MappedNotOverride - checks to see if we should really
  848.  *        put a twm frame on the window
  849.  *
  850.  *  Returned Value:
  851.  *    TRUE    - go ahead and frame the window
  852.  *    FALSE    - don't frame the window
  853.  *
  854.  *  Inputs:
  855.  *    w    - the window to check
  856.  *
  857.  ***********************************************************************
  858.  */
  859.  
  860. int
  861. MappedNotOverride(w)
  862.     Window w;
  863. {
  864.     XWindowAttributes wa;
  865.  
  866.     XGetWindowAttributes(dpy, w, &wa);
  867.     return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
  868. }
  869.  
  870.  
  871. /***********************************************************************
  872.  * 
  873.  *  Procedure:
  874.  *      AddDefaultBindings - attach default bindings so that naive users
  875.  *      don't get messed up if they provide a minimal twmrc.
  876.  */
  877. static void do_add_binding (button, context, modifier, func)
  878.     int button, context, modifier;
  879.     int func;
  880. {
  881.     MouseButton *mb = &Scr->Mouse[button][context][modifier];
  882.  
  883.     if (mb->func) return;        /* already defined */
  884.  
  885.     mb->func = func;
  886.     mb->item = NULL;
  887. }
  888.  
  889. AddDefaultBindings ()
  890. {
  891.     /*
  892.      * The bindings are stored in Scr->Mouse, indexed by
  893.      * Mouse[button_number][C_context][modifier].
  894.      */
  895.  
  896. #define NoModifierMask 0
  897.  
  898.     do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE);
  899.     do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY);
  900.     do_add_binding (Button1, C_ICONMGR, NoModifierMask, F_ICONIFY);
  901.  
  902.     do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER);
  903.     do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY);
  904.     do_add_binding (Button2, C_ICONMGR, NoModifierMask, F_ICONIFY);
  905.  
  906. #undef NoModifierMask
  907. }
  908.  
  909.  
  910.  
  911.  
  912. /***********************************************************************
  913.  *
  914.  *  Procedure:
  915.  *    GrabButtons - grab needed buttons for the window
  916.  *
  917.  *  Inputs:
  918.  *    tmp_win - the twm window structure to use
  919.  *
  920.  ***********************************************************************
  921.  */
  922.  
  923. void
  924. GrabButtons(tmp_win)
  925. TwmWindow *tmp_win;
  926. {
  927.     int i, j;
  928.  
  929.     for (i = 0; i < MAX_BUTTONS+1; i++)
  930.     {
  931.     for (j = 0; j < MOD_SIZE; j++)
  932.     {
  933.         if (Scr->Mouse[i][C_WINDOW][j].func != NULL)
  934.         {
  935.             /* twm used to do this grab on the application main window,
  936.                  * tmp_win->w . This was not ICCCM complient and was changed.
  937.          */
  938.         XGrabButton(dpy, i, j, tmp_win->frame, 
  939.                 True, ButtonPressMask | ButtonReleaseMask,
  940.                 GrabModeAsync, GrabModeAsync, None, 
  941.                 Scr->FrameCursor);
  942.         }
  943.     }
  944.     }
  945. }
  946.  
  947. /***********************************************************************
  948.  *
  949.  *  Procedure:
  950.  *    GrabKeys - grab needed keys for the window
  951.  *
  952.  *  Inputs:
  953.  *    tmp_win - the twm window structure to use
  954.  *
  955.  ***********************************************************************
  956.  */
  957.  
  958. void
  959. GrabKeys(tmp_win)
  960. TwmWindow *tmp_win;
  961. {
  962.     FuncKey *tmp;
  963.     IconMgr *p;
  964.  
  965.     for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
  966.     {
  967.     switch (tmp->cont)
  968.     {
  969.     case C_WINDOW:
  970.         XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
  971.         GrabModeAsync, GrabModeAsync);
  972.         break;
  973.  
  974.     case C_ICON:
  975.         if (tmp_win->icon_w)
  976.         XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
  977.             GrabModeAsync, GrabModeAsync);
  978.  
  979.     case C_TITLE:
  980.         if (tmp_win->title_w)
  981.         XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
  982.             GrabModeAsync, GrabModeAsync);
  983.         break;
  984.  
  985.     case C_NAME:
  986.         XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
  987.         GrabModeAsync, GrabModeAsync);
  988.         if (tmp_win->icon_w)
  989.         XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
  990.             GrabModeAsync, GrabModeAsync);
  991.         if (tmp_win->title_w)
  992.         XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
  993.             GrabModeAsync, GrabModeAsync);
  994.         break;
  995.     /*
  996.     case C_ROOT:
  997.         XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True,
  998.         GrabModeAsync, GrabModeAsync);
  999.         break;
  1000.     */
  1001.     }
  1002.     }
  1003.     for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
  1004.     {
  1005.     if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers)
  1006.     {
  1007.         for (p = &Scr->iconmgr; p != NULL; p = p->next)
  1008.         {
  1009.         XUngrabKey(dpy, tmp->keycode, tmp->mods, p->twm_win->w);
  1010.         }
  1011.     }
  1012.     }
  1013. }
  1014.  
  1015. static Window CreateHighlightWindow (tmp_win)
  1016.     TwmWindow *tmp_win;
  1017. {
  1018.     XSetWindowAttributes attributes;    /* attributes for create windows */
  1019.     Pixmap pm = None;
  1020.     GC gc;
  1021.     XGCValues gcv;
  1022.     unsigned long valuemask;
  1023.     int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
  1024.     Window w;
  1025.  
  1026.  
  1027.     /*
  1028.      * If a special highlight pixmap was given, use that.  Otherwise,
  1029.      * use a nice, even gray pattern.  The old horizontal lines look really
  1030.      * awful on interlaced monitors (as well as resembling other looks a
  1031.      * little bit too closely), but can be used by putting
  1032.      *
  1033.      *                 Pixmaps { TitleHighlight "hline2" }
  1034.      *
  1035.      * (or whatever the horizontal line bitmap is named) in the startup
  1036.      * file.  If all else fails, use the foreground color to look like a 
  1037.      * solid line.
  1038.      */
  1039.     if (!Scr->hilitePm) {
  1040.     Scr->hilitePm = XCreateBitmapFromData (dpy, tmp_win->title_w, 
  1041.                            gray_bits, gray_width, 
  1042.                            gray_height);
  1043.     Scr->hilite_pm_width = gray_width;
  1044.     Scr->hilite_pm_height = gray_height;
  1045.     }
  1046.     if (Scr->hilitePm) {
  1047.     pm = XCreatePixmap (dpy, tmp_win->title_w,
  1048.                 Scr->hilite_pm_width, Scr->hilite_pm_height,
  1049.                 Scr->d_depth);
  1050.     gcv.foreground = tmp_win->title.fore;
  1051.     gcv.background = tmp_win->title.back;
  1052.     gcv.graphics_exposures = False;
  1053.     gc = XCreateGC (dpy, pm,
  1054.             (GCForeground|GCBackground|GCGraphicsExposures),
  1055.             &gcv);
  1056.     if (gc) {
  1057.         XCopyPlane (dpy, Scr->hilitePm, pm, gc, 0, 0, 
  1058.             Scr->hilite_pm_width, Scr->hilite_pm_height,
  1059.             0, 0, 1);
  1060.         XFreeGC (dpy, gc);
  1061.     } else {
  1062.         XFreePixmap (dpy, pm);
  1063.         pm = None;
  1064.     }
  1065.     }
  1066.     if (pm) {
  1067.     valuemask = CWBackPixmap;
  1068.     attributes.background_pixmap = pm;
  1069.     } else {
  1070.     valuemask = CWBackPixel;
  1071.     attributes.background_pixel = tmp_win->title.fore;
  1072.     }
  1073.  
  1074.     w = XCreateWindow (dpy, tmp_win->title_w, 0, Scr->FramePadding,
  1075.                (unsigned int) Scr->TBInfo.width, (unsigned int) h,
  1076.                (unsigned int) 0,
  1077.                Scr->d_depth, (unsigned int) CopyFromParent,
  1078.                Scr->d_visual, valuemask, &attributes);
  1079.     if (pm) XFreePixmap (dpy, pm);
  1080.     return w;
  1081. }
  1082.  
  1083.  
  1084. void ComputeCommonTitleOffsets ()
  1085. {
  1086.     int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
  1087.  
  1088.     Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
  1089.     if (Scr->TBInfo.nleft > 0)
  1090.       Scr->TBInfo.leftx += Scr->ButtonIndent;
  1091.     Scr->TBInfo.titlex = (Scr->TBInfo.leftx +
  1092.               (Scr->TBInfo.nleft * buttonwidth) - Scr->TBInfo.pad +
  1093.               Scr->TitlePadding);
  1094.     if (Scr->TBInfo.nright > 0)
  1095.       Scr->TBInfo.rightoff += (Scr->ButtonIndent +
  1096.                    ((Scr->TBInfo.nright * buttonwidth) -
  1097.                 Scr->TBInfo.pad));
  1098.     return;
  1099. }
  1100.  
  1101. void ComputeWindowTitleOffsets (tmp_win, width, squeeze)
  1102.     TwmWindow *tmp_win;
  1103.     Bool squeeze;
  1104. {
  1105.     tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width);
  1106.     if (tmp_win->hilite_w || Scr->TBInfo.nright > 0) 
  1107.       tmp_win->highlightx += Scr->TitlePadding;
  1108.     tmp_win->rightx = width - Scr->TBInfo.rightoff;
  1109.     if (squeeze && tmp_win->squeeze_info) {
  1110.     int rx = (tmp_win->highlightx + 
  1111.           (tmp_win->hilite_w
  1112.             ? Scr->TBInfo.width * 2 : 0) +
  1113.           (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) +
  1114.           Scr->FramePadding);
  1115.     if (rx < tmp_win->rightx) tmp_win->rightx = rx;
  1116.     }
  1117.     return;
  1118. }
  1119.  
  1120.  
  1121. /*
  1122.  * ComputeTitleLocation - calculate the position of the title window; we need
  1123.  * to take the frame_bw into account since we want (0,0) of the title window
  1124.  * to line up with (0,0) of the frame window.
  1125.  */
  1126. void ComputeTitleLocation (tmp)
  1127.     register TwmWindow *tmp;
  1128. {
  1129.     tmp->title_x = -tmp->frame_bw;
  1130.     tmp->title_y = -tmp->frame_bw;
  1131.  
  1132.     if (tmp->squeeze_info) {
  1133.     register SqueezeInfo *si = tmp->squeeze_info;
  1134.     int basex;
  1135.     int maxwidth = tmp->frame_width;
  1136.     int tw = tmp->title_width;
  1137.  
  1138.     /*
  1139.      * figure label base from squeeze info (justification fraction)
  1140.      */
  1141.     if (si->denom == 0) {    /* num is pixel based */
  1142.         if ((basex = si->num) == 0) {  /* look for special cases */
  1143.         switch (si->justify) {
  1144.           case J_RIGHT:
  1145.             basex = maxwidth;
  1146.             break;
  1147.           case J_CENTER:
  1148.             basex = maxwidth / 2;
  1149.         break;
  1150.         }
  1151.         }
  1152.     } else {            /* num/denom is fraction */
  1153.         basex = ((si->num * maxwidth) / si->denom);
  1154.         if (si->num < 0) basex += maxwidth;
  1155.     }
  1156.  
  1157.     /*
  1158.      * adjust for left (nop), center, right justify and clip
  1159.      */
  1160.     switch (si->justify) {
  1161.       case J_CENTER:
  1162.         basex -= tw / 2;
  1163.         break;
  1164.       case J_RIGHT:
  1165.         basex -= tw - 1;
  1166.         break;
  1167.     }
  1168.     if (basex > maxwidth - tw + 1)
  1169.       basex = maxwidth - tw + 1;
  1170.     if (basex < 0) basex = 0;
  1171.  
  1172.     tmp->title_x = basex - tmp->frame_bw;
  1173.     }
  1174. }
  1175.  
  1176.  
  1177. static void CreateWindowTitlebarButtons (tmp_win)
  1178.     TwmWindow *tmp_win;
  1179. {
  1180.     unsigned long valuemask;        /* mask for create windows */
  1181.     XSetWindowAttributes attributes;    /* attributes for create windows */
  1182.     int leftx, rightx, y;
  1183.     TitleButton *tb;
  1184.     int nb;
  1185.  
  1186.     if (tmp_win->title_height == 0)
  1187.     {
  1188.     tmp_win->hilite_w = 0;
  1189.     return;
  1190.     }
  1191.  
  1192.  
  1193.     /*
  1194.      * create the title bar windows; let the event handler deal with painting
  1195.      * so that we don't have to spend two pixmaps (or deal with hashing)
  1196.      */
  1197.     ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False);
  1198.  
  1199.     leftx = y = Scr->TBInfo.leftx;
  1200.     rightx = tmp_win->rightx;
  1201.  
  1202.     attributes.win_gravity = NorthWestGravity;
  1203.     attributes.background_pixel = tmp_win->title.back;
  1204.     attributes.border_pixel = tmp_win->title.fore;
  1205.     attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
  1206.                  ExposureMask);
  1207.     attributes.cursor = Scr->ButtonCursor;
  1208.     valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask |
  1209.          CWCursor);
  1210.  
  1211.     tmp_win->titlebuttons = NULL;
  1212.     nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1213.     if (nb > 0) {
  1214.     tmp_win->titlebuttons = (TBWindow *) malloc (nb * sizeof(TBWindow));
  1215.     if (!tmp_win->titlebuttons) {
  1216.         fprintf (stderr, "%s:  unable to allocate %d titlebuttons\n", 
  1217.              ProgramName, nb);
  1218.     } else {
  1219.         TBWindow *tbw;
  1220.         int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
  1221.         unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2);
  1222.  
  1223.         for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
  1224.          tb = tb->next, tbw++) {
  1225.         int x;
  1226.         if (tb->rightside) {
  1227.             x = rightx;
  1228.             rightx += boxwidth;
  1229.             attributes.win_gravity = NorthEastGravity;
  1230.         } else {
  1231.             x = leftx;
  1232.             leftx += boxwidth;
  1233.             attributes.win_gravity = NorthWestGravity;
  1234.         }
  1235.         tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h,
  1236.                          (unsigned int) Scr->TBInfo.border,
  1237.                          0, (unsigned int) CopyFromParent,
  1238.                          (Visual *) CopyFromParent,
  1239.                          valuemask, &attributes);
  1240.         tbw->info = tb;
  1241.         }
  1242.     }
  1243.     }
  1244.  
  1245.     tmp_win->hilite_w = (tmp_win->titlehighlight 
  1246.              ? CreateHighlightWindow (tmp_win) : None);
  1247.  
  1248.     XMapSubwindows(dpy, tmp_win->title_w);
  1249.     if (tmp_win->hilite_w)
  1250.       XUnmapWindow(dpy, tmp_win->hilite_w);
  1251.     return;
  1252. }
  1253.  
  1254.  
  1255. SetHighlightPixmap (filename)
  1256.     char *filename;
  1257. {
  1258.     Pixmap pm = GetBitmap (filename);
  1259.  
  1260.     if (pm) {
  1261.     if (Scr->hilitePm) {
  1262.         XFreePixmap (dpy, Scr->hilitePm);
  1263.     }
  1264.     Scr->hilitePm = pm;
  1265.     Scr->hilite_pm_width = JunkWidth;
  1266.     Scr->hilite_pm_height = JunkHeight;
  1267.     }
  1268. }
  1269.  
  1270.  
  1271. FetchWmProtocols (tmp)
  1272.     TwmWindow *tmp;
  1273. {
  1274.     unsigned long flags = 0L;
  1275.     Atom *protocols = NULL;
  1276.     int n;
  1277.  
  1278.     if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) {
  1279.     register int i;
  1280.     register Atom *ap;
  1281.  
  1282.     for (i = 0, ap = protocols; i < n; i++, ap++) {
  1283.         if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus;
  1284.         if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself;
  1285.         if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow;
  1286.     }
  1287.     if (protocols) XFree ((char *) protocols);
  1288.     }
  1289.     tmp->protocols = flags;
  1290. }
  1291.  
  1292. TwmColormap *
  1293. CreateTwmColormap(c)
  1294.     Colormap c;
  1295. {
  1296.     TwmColormap *cmap;
  1297.     cmap = (TwmColormap *) malloc(sizeof(TwmColormap));
  1298.     if (!cmap ||
  1299.     XSaveContext(dpy, c, ColormapContext, (caddr_t) cmap)) {
  1300.     if (cmap) free((char *) cmap);
  1301.     return (NULL);
  1302.     }
  1303.     cmap->c = c;
  1304.     cmap->state = 0;
  1305.     cmap->install_req = 0;
  1306.     cmap->w = None;
  1307.     cmap->refcnt = 1;
  1308.     return (cmap);
  1309. }
  1310.  
  1311. ColormapWindow *
  1312. CreateColormapWindow(w, creating_parent, property_window)
  1313.     Window w;
  1314.     Bool creating_parent;
  1315.     Bool property_window;
  1316. {
  1317.     ColormapWindow *cwin;
  1318.     TwmColormap *cmap;
  1319.     XWindowAttributes attributes;
  1320.  
  1321.     cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow));
  1322.     if (cwin) {
  1323.     if (!XGetWindowAttributes(dpy, w, &attributes) ||
  1324.         XSaveContext(dpy, w, ColormapContext, (caddr_t) cwin)) {
  1325.         free((char *) cwin);
  1326.         return (NULL);
  1327.     }
  1328.  
  1329.     if (XFindContext(dpy, attributes.colormap,  ColormapContext,
  1330.         (caddr_t *)&cwin->colormap) == XCNOENT) {
  1331.         cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
  1332.         if (!cmap) {
  1333.         XDeleteContext(dpy, w, ColormapContext);
  1334.         free((char *) cwin);
  1335.         return (NULL);
  1336.         }
  1337.     } else {
  1338.         cwin->colormap->refcnt++;
  1339.     }
  1340.  
  1341.     cwin->w = w;
  1342.     /*
  1343.      * Assume that windows in colormap list are
  1344.      * obscured if we are creating the parent window.
  1345.      * Otherwise, we assume they are unobscured.
  1346.      */
  1347.     cwin->visibility = creating_parent ?
  1348.         VisibilityPartiallyObscured : VisibilityUnobscured;
  1349.     cwin->refcnt = 1;
  1350.  
  1351.     /*
  1352.      * If this is a ColormapWindow property window and we
  1353.      * are not monitoring ColormapNotify or VisibilityNotify
  1354.      * events, we need to.
  1355.      */
  1356.     if (property_window &&
  1357.         (attributes.your_event_mask &
  1358.         (ColormapChangeMask|VisibilityChangeMask)) !=
  1359.             (ColormapChangeMask|VisibilityChangeMask)) {
  1360.         XSelectInput(dpy, w, attributes.your_event_mask |
  1361.         (ColormapChangeMask|VisibilityChangeMask));
  1362.     }
  1363.     }
  1364.  
  1365.     return (cwin);
  1366. }
  1367.         
  1368. FetchWmColormapWindows (tmp)
  1369.     TwmWindow *tmp;
  1370. {
  1371.     register int i, j;
  1372.     Window *cmap_windows = NULL;
  1373.     Bool can_free_cmap_windows = False;
  1374.     int number_cmap_windows = 0;
  1375.     ColormapWindow **cwins = NULL;
  1376.     int previously_installed;
  1377.     extern void free_cwins();
  1378.  
  1379.     number_cmap_windows = 0;
  1380.  
  1381.     if (/* SUPPRESS 560 */previously_installed = 
  1382.        (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins)) {
  1383.     cwins = tmp->cmaps.cwins;
  1384.     for (i = 0; i < tmp->cmaps.number_cwins; i++)
  1385.         cwins[i]->colormap->state = 0;
  1386.     }
  1387.  
  1388.     if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows, 
  1389.                    &number_cmap_windows) &&
  1390.     number_cmap_windows > 0) {
  1391.  
  1392.     can_free_cmap_windows = False;
  1393.     /*
  1394.      * check if the top level is in the list, add to front if not
  1395.      */
  1396.     for (i = 0; i < number_cmap_windows; i++) {
  1397.         if (cmap_windows[i] == tmp->w) break;
  1398.     }
  1399.     if (i == number_cmap_windows) {     /* not in list */
  1400.         Window *new_cmap_windows =
  1401.           (Window *) malloc (sizeof(Window) * (number_cmap_windows + 1));
  1402.  
  1403.         if (!new_cmap_windows) {
  1404.         fprintf (stderr, 
  1405.              "%s:  unable to allocate %d element colormap window array\n",
  1406.             ProgramName, number_cmap_windows+1);
  1407.         goto done;
  1408.         }
  1409.         new_cmap_windows[0] = tmp->w;  /* add to front */
  1410.         for (i = 0; i < number_cmap_windows; i++) {     /* append rest */
  1411.         new_cmap_windows[i+1] = cmap_windows[i];
  1412.         }
  1413.         XFree ((char *) cmap_windows);
  1414.         can_free_cmap_windows = True;  /* do not use XFree any more */
  1415.         cmap_windows = new_cmap_windows;
  1416.         number_cmap_windows++;
  1417.     }
  1418.  
  1419.     cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *) *
  1420.         number_cmap_windows);
  1421.     if (cwins) {
  1422.         for (i = 0; i < number_cmap_windows; i++) {
  1423.  
  1424.         /*
  1425.          * Copy any existing entries into new list.
  1426.          */
  1427.         for (j = 0; j < tmp->cmaps.number_cwins; j++) {
  1428.             if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
  1429.             cwins[i] = tmp->cmaps.cwins[j];
  1430.             cwins[i]->refcnt++;
  1431.             break;
  1432.             }
  1433.         }
  1434.  
  1435.         /*
  1436.          * If the colormap window is not being pointed by
  1437.          * some other applications colormap window list,
  1438.          * create a new entry.
  1439.          */
  1440.         if (j == tmp->cmaps.number_cwins) {
  1441.             if (XFindContext(dpy, cmap_windows[i], ColormapContext,
  1442.                      (caddr_t *)&cwins[i]) == XCNOENT) {
  1443.             if ((cwins[i] = CreateColormapWindow(cmap_windows[i],
  1444.                     (Bool) tmp->cmaps.number_cwins == 0,
  1445.                     True)) == NULL) {
  1446.                 int k;
  1447.                 for (k = i + 1; k < number_cmap_windows; k++)
  1448.                 cmap_windows[k-1] = cmap_windows[k];
  1449.                 i--;
  1450.                 number_cmap_windows--;
  1451.             }
  1452.             } else
  1453.             cwins[i]->refcnt++;
  1454.         }
  1455.         }
  1456.     }
  1457.     }
  1458.  
  1459.     /* No else here, in case we bailed out of clause above.
  1460.      */
  1461.     if (number_cmap_windows == 0) {
  1462.  
  1463.     number_cmap_windows = 1;
  1464.  
  1465.     cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *));
  1466.     if (XFindContext(dpy, tmp->w, ColormapContext, (caddr_t *)&cwins[0]) ==
  1467.         XCNOENT)
  1468.         cwins[0] = CreateColormapWindow(tmp->w,
  1469.                 (Bool) tmp->cmaps.number_cwins == 0, False);
  1470.     else
  1471.         cwins[0]->refcnt++;
  1472.     }
  1473.  
  1474.     if (tmp->cmaps.number_cwins)
  1475.     free_cwins(tmp);
  1476.  
  1477.     tmp->cmaps.cwins = cwins;
  1478.     tmp->cmaps.number_cwins = number_cmap_windows;
  1479.     if (number_cmap_windows > 1)
  1480.     tmp->cmaps.scoreboard = 
  1481.       (char *) calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
  1482.         
  1483.     if (previously_installed)
  1484.     InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
  1485.  
  1486.   done:
  1487.     if (cmap_windows) {
  1488.     if (can_free_cmap_windows)
  1489.       free ((char *) cmap_windows);
  1490.     else
  1491.       XFree ((char *) cmap_windows);
  1492.     }
  1493.  
  1494.     return;
  1495. }
  1496.  
  1497.  
  1498. void GetWindowSizeHints (tmp)
  1499.     TwmWindow *tmp;
  1500. {
  1501.     long supplied = 0;
  1502.  
  1503.     if (!XGetWMNormalHints (dpy, tmp->w, &tmp->hints, &supplied))
  1504.       tmp->hints.flags = 0;
  1505.  
  1506.     if (tmp->hints.flags & PResizeInc) {
  1507.     if (tmp->hints.width_inc == 0) tmp->hints.width_inc = 1;
  1508.     if (tmp->hints.height_inc == 0) tmp->hints.height_inc = 1;
  1509.     }
  1510.  
  1511.     if (!(supplied & PWinGravity) && (tmp->hints.flags & USPosition)) {
  1512.     static int gravs[] = { SouthEastGravity, SouthWestGravity,
  1513.                    NorthEastGravity, NorthWestGravity };
  1514.     int right =  tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
  1515.     int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
  1516.     tmp->hints.win_gravity = 
  1517.       gravs[((Scr->MyDisplayHeight - bottom < tmp->title_height) ? 0 : 2) |
  1518.         ((Scr->MyDisplayWidth - right   < tmp->title_height) ? 0 : 1)];
  1519.     tmp->hints.flags |= PWinGravity;
  1520.     }
  1521. }
  1522.